#include "constants.h"

private ["_debug","_can_run","_player_number","_wait_time","_convoys","_convoy","_units","_alive_units","_vec_types","_alive_vehicles"];
_debug = true;
_can_run = true;
_player_number = 0;
_wait_time = 1800;
_vehicle_patrol = true;
// Contains a list of all convoys which have been spawn.
// One convoy is described with: [Zone,SpawnTime,StartPos,ObjectName,[unit1,unit2,unit3,..]]
_convoys = [];
_sector_spawn_times = [];
_own_side = switch (d_own_side) do {case "EAST": {east};case "WEST": {west};case "GUER": {resistance};case "CIV": {civilian}; default{west};};

if (typeName _this == "ARRAY") then {
	if (count _this > 0) then {	_vehicle_patrol = _this select 0; };
	if (count _this > 1) then {	_debug = _this select 1; };
};
If (isNil "D_LAST_RANDOM_SPAWN_ID") then {D_LAST_RANDOM_SPAWN_ID = 1;};

// Checks that no player is around, then destroy all the given units and their crew
// Everything will be cleaned up automatically through the clean up system.
_fnc_delayed_destroy = {
	private ["_wait","_units","_unit","_found","_alive","_position"];
	_wait = true;
	_units = _this;
	while {_wait} do {
		_alive = false;
		{
			_unit = _x;
			if (!isNull _unit) then {
				_position = getPos _unit;
				if (_position distance [0,0,0] > 1) then {
					_found = false;
					{
						if (_x distance _position < 300) exitWith {_found = true; };
					} foreach playableUnits;
					if (_found) then {
						_alive = true;
					} else {
						deleteVehicle _unit;
					};
				} else {
					deleteVehicle _unit;
				};
			};
		} foreach _units;
		if (_alive) then {
			sleep (150 + random(100));
		} else {
			diag_log Format["(%1)[%2]: %3",diag_tickTime,"randomconvoy.sqf","Delayed Destroy Done"];
			_wait = false;
		};
	};
};

while {_can_run} do {
	if (_debug) then { diag_log Format["(%1)[%2]: %3 (%4)",diag_tickTime,"randomconvoy.sqf","Starting",Time];};
	if ((_vehicle_patrol && WithRandomConvoy) || (!_vehicle_patrol && WithRandomPatrols))then {
		_max_patrols = RandomPatrolsCount;
		if (_vehicle_patrol) then {_max_patrols = RandomConvoysCount;};
		// We will spawn two convoys each time. One in the north of the island, the other in the south part
		// The code will check every now and then if a convoy needs to be spawned or not.
		_player_number = call XPlayersNumber;
		if (_player_number > 0) then {
			if (_debug) then { diag_log Format["(%1)[%2]: %3: %4 (%5)",diag_tickTime,"randomconvoy.sqf","Players online",_player_number,(count _convoys)];};
			
			// ----------------------------------------------------------------------
			//   Check current convoys, and queue for delete those which are down
			// ----------------------------------------------------------------------
			If ((count _convoys) > 0) then {
				if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomconvoy.sqf","Checking active convoys",_convoys];};
				for [{_i = 0},{_i < count _convoys},{_i = _i + 1}] do {
					_convoy = _convoys select _i;
					_units = _convoy select XF_SPAWN_ARRAY_UNITSARRAY;
					_alive_vehicles = [];
					_alive_units = [];
					{
						if (!IsNull _x) then {
							// An alive unit which cannot move or which is too wounded... doesn't interest us.
							if ((alive _x) && (canMove _x) && (damage _x < 0.5)) then {
								if (_x isKindOf "LandVehicle") then {
									_alive_vehicles set [count _alive_vehicles, typeOf(_x)];
								} else {
									_alive_units set [count _alive_units, typeOf(_x)];
								};
							};
						};
					}foreach _units;
					// For a vehicle patrol, we're only interested in the alive vecs, for a soldier patrol, only in the non vehicles
					if (((count _alive_vehicles > 0) && _vehicle_patrol)|| ((count _alive_units > 0) && !_vehicle_patrol)) then {
						if (_debug) then { diag_log Format["(%1)[%2]: %3: %4 - %5",diag_tickTime,"randomconvoy.sqf","Alive",_alive_vehicles,_alive_units];};
					} else {
						if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomconvoy.sqf","Queued for deletion",_convoy];};
						_sector = _convoy select XF_SPAWN_ARRAY_SECTOR;
						_wait_time = switch (true) do {
							case (_player_number <= 5): {1800};
							case (_player_number <= 10): {1200};
							case (_player_number <= 15): {600};
							case (_player_number <= 20): {300};
							default {120};
						};
						_sector_spawn_times set [_sector, (time + _wait_time)];
						_units call _fnc_delayed_destroy;
						_convoys set [_i,"XxDelxX"];
					};
				};
				_convoys = _convoys - ["XxDelxX"];
			};
			// ----------------------------------------------------------------------
			//   Spawn more convoys if needed.
			// ----------------------------------------------------------------------
			If ((count _convoys) < _max_patrols) then {
				// We filter out only the sectors which are designed for random spawn
				_spawn_sectors = [d_map_sectors,[XF_SECTOR_ARRAY_TYPE,"==",XF_SECTOR_TYPE_SPAWN]] call XfTableFilter;
				if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomconvoy.sqf","Spawn Sectors",_spawn_sectors];};
				// Next we check which sectors are already active.
				_current_sectors = [];
				{	_sector = _x select XF_SPAWN_ARRAY_SECTOR;
					if !(_sector in _current_sectors) then {_current_sectors set [count _current_sectors, _sector];};
				} foreach _convoys;
				// If there are as many active sectors as possible sectors, we just pick one randomly.
				_sector = -1;
				if ((count _current_sectors) >= (count _spawn_sectors)) then {
					_sector = floor(random(count _spawn_sectors));
				} else {
					_select_sectors = [];
					for [{_i = 0},{_i < count _spawn_sectors},{_i = _i + 1}] do {
						if !(_i in _current_sectors) then {_select_sectors set [count _select_sectors, _i];};
					};
					_sector = _select_sectors call XfRandomArrayVal;
				};
				// Now we should have a valid sector
				if (_sector >= 0 && _sector < count _spawn_sectors) then {
					// Next thing, we check when a convoy was last spawned in this sector.
					_next_spawn = 0;
					if (_sector < count _sector_spawn_times) then { _next_spawn = _sector_spawn_times select _sector};
					if (isNil "_next_spawn") then {_next_spawn = 0};
					// If the spawn interval has passed, we can spawn a new one.
					if (_debug) then { diag_log Format["(%1)[%2]: %3: %4 (%5)",diag_tickTime,"randomconvoy.sqf","Selected sector",_sector,_next_spawn];};
					if (time > _next_spawn) then {
						// Ok... now we can try to spawn a convoy :-)
						_spawn_sector = _spawn_sectors select _sector;
						_shape_arrays = _spawn_sector select XF_SECTOR_ARRAY_SHAPE_ARRAY;
						if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomconvoy.sqf","Sector Shapes",_shape_arrays];};
						// _sector_rectangle = _spawn_sector select XF_SECTOR_ARRAY_RECTANGLE;
						// _sector_center = _spawn_sector select XF_SECTOR_ARRAY_CENTER;
						// _sector_width = _spawn_sector select XF_SECTOR_ARRAY_WIDTH;
						// _sector_height = _spawn_sector select XF_SECTOR_ARRAY_HEIGHT;
						// _sector_angle = _spawn_sector select XF_SECTOR_ARRAY_ANGLE;
						_grp = objNull;
						_convoy = [];
						_eligible_towns = [d_map_locations, [XF_MAP_LOCATION_TYPE,"IN",[XF_MAP_LOCATION_TYPE_TOWN,XF_MAP_LOCATION_TYPE_VILLAGE]]] call XfTableFilter;
						if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomconvoy.sqf","Eligible Towns",_eligible_towns];};
						_towns = [];
						{
							_town = _x;
							_valid = false;
							{
								_valid = [(_town select XF_MAP_LOCATION_CENTER), _x] call XfPointInShape;
								if (_valid) exitWith {_towns set [ count _towns, _town ]; };
							}foreach _shape_arrays;
							// If (_sector_rectangle) then {
								// _valid = [(_town select XF_MAP_LOCATION_CENTER), _sector_center, _sector_width, _sector_height, _sector_angle] call XfPointInSquare;
							// } else {
								// _valid = [(_town select XF_MAP_LOCATION_CENTER), _sector_center, _sector_width] call XfPointInCircle;
							// };
						} foreach _eligible_towns;
						// We randomize the result array
						_towns = _towns call XfRandomArray;
						sleep 1;
						// And again to ensure a better randomization (not that I don't trust "Random"...)
						_towns = _towns call XfRandomArray;
						if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomconvoy.sqf","Towns",_towns];};
						_tries = 30;
						_best_spot = [[],0,10000000];
						while {_tries > 0} do {
							_start_town = _towns call XfRandomArrayVal;
							_spot = [_start_town select XF_MAP_LOCATION_CENTER, _start_town select XF_MAP_LOCATION_SIZE] call XfGetRanPointCircle;
							If (count _spot == 3) then {
								_roads = (_spot nearRoads (_start_town select XF_MAP_LOCATION_SIZE));
								if (count _roads > 0) then {
									{
										_spot = (getPos _x) findEmptyPosition [0,30];
										if (count _spot == 3) exitWith {};
									} foreach _roads;
								} else {
									_spot = [];
								};
								if (count _spot == 3) then {
									if (_debug) then { diag_log Format["(%1)[%2]: %3: %4 %5",diag_tickTime,"randomconvoy.sqf","Testing spot", _spot, _start_town]; };
									_lst = nearestObjects [_spot, ["Man","Car","Tank","Ship"], 400];
									_density = 0;
									{
										if ((side _x) == _own_side) then {
											if (_debug) then { diag_log Format["(%1)[%2]: %3: %4 (%5)",diag_tickTime,"randomconvoy.sqf","Own Side", _x,(isplayer _x)]; };
											if (isplayer _x) then {
												// If a humen player is present, then we highly increase the density to reject as much as possible those spots
												_density = _density + (10000 / (_x distance _spot));
											} else {
												_density = _density + (2000 / (_x distance _spot));
											};
										};
									} foreach _lst;
									// We factor in the fact many units are present, to avoid spawning in an already crowded place
									_density = _density + (count _lst) * 50;
									if (_density < (_best_spot select 2)) then {
										// We update the best spot
										_best_spot = [_spot, 0, _density];
										// We lower the tries count to narrow a good spot more quickly
										_tries = _tries - 3;
										if (_debug) then { diag_log Format["(%1)[%2]: %3: %4 (%5)",diag_tickTime,"randomconvoy.sqf","New best spot", _best_spot,_tries]; };
									};
								};
							};
							_tries = _tries - 1;
							sleep 0.5;
						};
						if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomconvoy.sqf","Selected spot",_best_spot];};
						_spot = _best_spot select 0;
						If (count _spot == 3) then {
							// From here, we know where to start.
							// Now we need a list of towns to go to.
							if (count _towns > 0) then {
								if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomconvoy.sqf","Towns",_towns];};
								
								// Now... we know where to send the convoy to :-)
								// We can start to create it.
								_units = [];
								if (_vehicle_patrol) then {
									_unit = [d_enemy_side_char,1,XF_VEHICLE_TYPES_TANK] call XfMissionGetRandomVehicleUnits;
									if (count _unit > 0) then {_units = [_units,_unit] call XfArrayPushStack;};
									_unit = [d_enemy_side_char,1,XF_VEHICLE_TYPES_LIGHTAPC] call XfMissionGetRandomVehicleUnits;
									if (count _unit > 0) then {_units = [_units,_unit] call XfArrayPushStack;};
									_unit = [d_enemy_side_char,1,XF_VEHICLE_TYPES_HEAVYWHEEL] call XfMissionGetRandomVehicleUnits;
									if (count _unit > 0) then {_units = [_units,_unit] call XfArrayPushStack;};
								} else {
									_units = [d_enemy_side_char,1,floor(random(5))] call XfMissionGetRandomFootmenUnits;
								};
								if (count _units > 0) then {
									if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomconvoy.sqf","Units",_units];};
									_convoy_units = [];
									_grp = [d_enemy_side] call x_creategroup;
									_grp setBehaviour "SAFE";
									_grp setFormation "STAG COLUMN";
									_grp allowFleeing 0;
									_leader = objNull;
									_veh = objNull;
									{
										if (_x isKindOf "Man") then {
											_veh = [_x, _grp, _spot, 5] call XfCreateUnit;
											// _veh = _grp createUnit [_x, _spot, [], 2, "FORM"];
										} else {
											_veh = createVehicle [_x, _spot, [], 2, "FORM"];
											if (((_veh isKindOf "Car") && (d_LockCars>0)) || ((_veh isKindOf "Tank") && (d_LockArmored>0)) || ((_veh isKindOf "Air") && (d_LockAir>0))) then {
												_veh lock true;
											};
										};
										_convoy_units set [count _convoy_units, _veh];
										if !(_veh isKindOf "Man") then {
											_crew = [_veh, _grp] call XfSpawnCrew;
											{ _convoy_units set [count _convoy_units, _x];
											} foreach crew _veh;
										};
										if (isNull _leader) then {
											_leader = leader _grp;
											_leader setRank "COLONEL";
										};
										sleep 1;
									} foreach _units;
									_convoy_units doFollow _leader;
									sleep 10;
									if (count _convoy_units > 0) then {
										if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomconvoy.sqf","Convoy Units",(count _convoy_units)];};
										{
											_wp = _grp addWayPoint [_x select XF_MAP_LOCATION_CENTER, _x select XF_MAP_LOCATION_SIZE];
											_wp setWaypointSpeed  "LIMITED";
											_wp setWaypointCompletionRadius ((_x select XF_MAP_LOCATION_SIZE) / 2);
											_wp setWaypointType "MOVE";
											_wp setWaypointFormation "STAG COLUMN";
											_wp setWaypointBehaviour "SAFE";
											_wp setWaypointTimeout [5, 10, 25];
											// gives a 33% chance to select a random waypoint
											_wp setWaypointStatements ["true", "if ((random 3) > 2) then { _nextWP = ((floor (random ((count (waypoints (group this)))-1))) + 1); diag_log Format['%1 NextWP %2',group this, _nextWP];  group this setCurrentWaypoint [(group this), _nextWP];};"];
											sleep 1;
										} foreach _towns;
										_wp = _grp addWayPoint [_spot, 100];
										_wp setWaypointSpeed  "LIMITED";
										_wp setWaypointCompletionRadius (100);
										_wp setWaypointType "CYCLE";
										_wp setWaypointBehaviour "SAFE";
										if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomconvoy.sqf","Waypoints done",(count _towns)];};

										_convoy set [XF_SPAWN_ARRAY_SECTOR,_sector];
										_convoy set [XF_SPAWN_ARRAY_SPAWNTIME,Time];
										_convoy set [XF_SPAWN_ARRAY_STARTPOS,_spot];
										if (_vehicle_patrol) then {
											_convoy set [XF_SPAWN_ARRAY_OBJECTNAME,Format["CONVOY%1",D_LAST_RANDOM_SPAWN_ID]];
										} else {
											_convoy set [XF_SPAWN_ARRAY_OBJECTNAME,Format["PATROL%1",D_LAST_RANDOM_SPAWN_ID]];
										};
										D_LAST_RANDOM_SPAWN_ID = D_LAST_RANDOM_SPAWN_ID + 1;
										_convoy set [XF_SPAWN_ARRAY_RADIUS,0];
										_convoy set [XF_SPAWN_ARRAY_GROUP,_grp];
										_convoy set [XF_SPAWN_ARRAY_UNITSARRAY,_convoy_units];
										_convoy set [XF_SPAWN_ARRAY_OBJECTSARRAY,[]];
										_convoy set [XF_SPAWN_ARRAY_MARKERSARRAY,[]];
									};
									if (_vehicle_patrol) then {
										// [(vehicle _leader), (_convoy select XF_SPAWN_ARRAY_OBJECTNAME),"ColorRed","o_motor_inf"] spawn XfAirMarkerMove;
										[_grp, (_convoy select XF_SPAWN_ARRAY_OBJECTNAME),"ColorRed","o_motor_inf","ShowPatrolMarkers"] spawn XfGroupMarkerMove;
									} else {
										// [(vehicle _leader), (_convoy select XF_SPAWN_ARRAY_OBJECTNAME),"ColorRedAlpha","o_inf"] spawn XfAirMarkerMove;
										[_grp, (_convoy select XF_SPAWN_ARRAY_OBJECTNAME),"ColorRed","o_inf","ShowPatrolMarkers"] spawn XfGroupMarkerMove;
									};
								};
								if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomconvoy.sqf","Convoy",_convoy];};
							};
						};
						// If we succeeded in spawning a convoy...
						if (count _convoy > 0) then {
							_convoys set [count _convoys, _convoy];
						};
					};
				};
			};
			if (_debug) then { diag_log Format["(%1)[%2]: %3: %4 (%5)",diag_tickTime,"randomconvoy.sqf","Spawn Times",_sector_spawn_times, count _convoys];};
			sleep (120 + random(60));
		} else {
			// Wait 5 mins before checking again if a player is there or not.
			if (_debug) then { diag_log Format["(%1)[%2]: %3",diag_tickTime,"randomconvoy.sqf","No players online"];};
			sleep 300;
		};
	} else {
		// Wait 5 minutes before checking again convoys are activated
		if (_debug) then { diag_log Format["(%1)[%2]: %3",diag_tickTime,"randomconvoy.sqf","Random Convoy Disabled"];};
		sleep 300;
	};
};